﻿/* ***********************************************
 * Author		:  kingthy
 * Email		:  kingthy@gmail.com
 * Description	:  Settings
 *
 * ***********************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.IO;
using System.Collections.Specialized;
using System.Xml;
using KT.Core.Extensions;
namespace KT.Core
{
    /// <summary>
    /// 参数配置,主要用于代替.NET中的AppSettings
    /// </summary>
    public static class Settings
    {
        /// <summary>
        /// 返回存储配置文件所在的基路径，默认是应用程序目录下的"config"目录；
        /// 或者可以在应用程序配置文件(app.config或web.config)里的AppSettings节点设置"KT.SETTINGS.BASEPATH"项，如
        /// &lt;add key="KT.SETTINGS.BASEPATH" value="~/config/" /&gt;，其中value可以设置为绝对或相对于应用程序的目录地址。
        /// </summary>
        public static string BasePath
        {
            get
            {
                string basePath = ConfigurationManager.AppSettings["KT.SETTINGS.BASEPATH"];
                if (string.IsNullOrEmpty(basePath))
                {
                    basePath = @"~/config/";
                }
                return Utility.ToAbsolutePath(basePath);
            }
        }

        /// <summary>
        /// 将文件地址转换为相对于存储配置文件的基路径的绝对路径地址
        /// </summary>
        public static string ToRelativeBasePath(string fileName)
        {
            if (Utility.IsAbsolutePath(fileName)) return fileName;

            return Path.Combine(BasePath, fileName.TrimStart(new char[] { '~', '\\', '/' }));
        }

        /// <summary>
        /// 获取默认的配置参数。此默认配置参数存储于基路径下的"settings.config"文件。
        /// </summary>
        public static NameValueCollection Default
        {
            get
            {
                return From("settings.config");
            }
        }

        /// <summary>
        /// 从配置文件获取配置参数
        /// </summary>
        /// <param name="fileName">配置文件地址，可以为绝对地址或者相对地址（相对于基路径）</param>
        /// <returns></returns>
        public static NameValueCollection From(string fileName)
        {
            fileName = ToRelativeBasePath(fileName);
            if (!File.Exists(fileName)) return new NameValueCollection();

            string key = "KT.SETTINGS.FILES." + fileName;
            var value = Cache.Get(key) as NameValueCollection;
            if (value == null)
            {
                List<string> dependFiles = new List<string>();
                value = LoadFromFile(fileName, dependFiles);
                Cache.Add(key, dependFiles.ToArray());
            }
            return value;
        }

        /// <summary>
        /// 从配置文件获取配置参数并映射为某个实体类
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public static T GetFrom<T>(string fileName)
            where T : class, new()
        {
            fileName = ToRelativeBasePath(fileName);
            if (!File.Exists(fileName)) return null;

            string key = "KT.SETTINGS.CLASSES." + fileName;
            var value = Cache.Get(key) as T;
            if (value == null)
            {
                List<string> dependFiles = new List<string>();
                var settings = LoadFromFile(fileName, dependFiles);
                value = new T();
                settings.CopyTo<T>(value);
                Cache.Add(key, value, dependFiles.ToArray());
            }
            return value;
        }

        /// <summary>
        /// 读取XML配置文件
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="dependFiles"></param>
        /// <returns></returns>
        private static NameValueCollection LoadFromFile(string fileName, List<string> dependFiles)
        {
            dependFiles.Add(fileName); //相关联的文件
            NameValueCollection values = new NameValueCollection();
            using (XmlTextReader reader = new XmlTextReader(fileName))
            {
                while (reader.Read())
                {
                    if (reader.Depth == 1 && reader.NodeType == XmlNodeType.Element && !string.IsNullOrEmpty(reader.Name))
                    {
                        //处理节点元素
                        string name = reader.Name;
                        string value = null;
                        if (reader.HasAttributes && name.Equals("add", StringComparison.InvariantCultureIgnoreCase)
                            && !string.IsNullOrEmpty(reader.GetAttribute("key")) 
                            )
                        {
                            //<add key="" value="" />
                            name = reader.GetAttribute("key");
                            value = reader.GetAttribute("value");
                        }
                        else if (reader.HasAttributes
                            && (name.Equals("include", StringComparison.InvariantCultureIgnoreCase))
                            && !string.IsNullOrEmpty(reader.GetAttribute("file")))
                        {
                            //<include file="" /> 的样式
                            string file = reader.GetAttribute("file");
                            if (!Utility.IsAbsolutePath(file))
                                file = Path.Combine(Path.GetDirectoryName(fileName), file);
                            if (File.Exists(file))
                            {
                                NameValueCollection items = LoadFromFile(file, dependFiles);
                                for (var i = 0; i < items.Count; i++)
                                {
                                    string key = items.GetKey(i);
                                    string kv = items[key];
                                    if (key != null && kv != null)
                                    {
                                        values.Set(key, kv);
                                    }
                                }
                            }
                            continue;
                        }
                        else
                        {
                            //<UserName>值</UserName> 的样式
                            value = reader.ReadString();
                        }
                        if (!string.IsNullOrEmpty(name)) values.Set(name, value);
                    }
                }
            }
            return values;
        }
    }
}
